#include "../h/Market.h"
#include <vector>
#include <string>
#include "User.h"
#include <iostream>
#include "ObjectsContainer.h"
#include "AppLogger.h"
#include "Reading.h"
using namespace std;
using namespace Poco;
Market::Market(vector<User*> users_, double price,bool sayaOn_)
{

	this->users = users_;
	this->amounts = new ObjectsContainer();
	this->prices = new ObjectsContainer();
	initPrices(price);
	this->sayaBuying = new ObjectsContainer();
	this->sayaSelling = new ObjectsContainer();
	this->sayaSell = false;
	this -> sayaOn = sayaOn_;
}

Market::~Market()
{
	delete amounts;
	delete prices;
	delete sayaBuying;
	delete sayaSelling;
}

void Market::initPrices(double price)
{
	prices->add("oil",price);
	prices->add("sun",price);
	prices->add("gas",price);
	prices->add("smile",price);
	prices->add("wind",price);
	prices->add("coal",price);
	prices->add("hug",price);
}

void Market::deal(Event buying,Event selling)
{
	double price = (buying.getPrice()+selling.getPrice())/2;
	string sellerName="", buyerName="";

	int energyAmount = min(selling.getAmount(),buying.getAmount());
	vector<User*>::iterator it;
	for(it = users.begin(); it<users.end(); it++)
	{
		User* j = *it;
		//Buyer
		if(j->getID()==buying.getUser())
		{
			buyerName = j -> getName();
			j->withdraw(price*energyAmount*1.005);
			j->addEnergy(buying.getEnergyType(),energyAmount);
		}
		//Seller
		if(j->getID()==selling.getUser())
		{
			sellerName = j -> getName();
			j->deposit(price*energyAmount*0.995);
			j->removeEnergy(buying.getEnergyType(),energyAmount);
		}
	}

	string message = "user " + sellerName + " sold to user " + buyerName +" a " + Reading::doubleToString(energyAmount) + " of "
	+ buying.getEnergyType() + " for a "+ Reading::doubleToString(price);
	CAppLogger::Instance().Log(message,Message::PRIO_NOTICE);

	// N = the number of energy sold in the last deal
	double N = energyAmount;
	// P = is the price of energy in the last deal
	double P = price;
	// T = total number of energy units in the market
	double T = amounts->getNameAmount(selling.getEnergyType());
	// the old energy price
	double OV = prices->getNameAmount(selling.getEnergyType());
	// the new value
	double NewPrice = ((N*P)+((T-N)*OV))/T;
	if(NewPrice!=OV)
	{
		string message1 = "Energy " + buying.getEnergyType() + " value changes from " + Reading::doubleToString(OV) + " to " +
							Reading::doubleToString(NewPrice);
		CAppLogger::Instance().Log(message1,Message::PRIO_WARNING);
	}
	prices->add(selling.getEnergyType(),NewPrice-OV);
	if (sayaOn)
	{
		if((NewPrice>OV)&&(selling.getUser()!="62")&&(buying.getUser()!="62"))
		{
			sayaBuying->add(selling.getEnergyType());
		}
		else if((NewPrice<OV)&&(selling.getUser()!="62")&&(buying.getUser()!="62"))
		{
			sayaBuying->remove(selling.getEnergyType(),sayaBuying->getNameAmount(selling.getEnergyType()));
			sayaSelling->add(selling.getEnergyType());
		}
	}

}
void Market::addEnergyAmount(string name,int amount)
{
	this->amounts->add(name,amount);
}

void Market::removeEnergyAmount(string name,double amount)
{
	this->amounts->remove(name,amount);
}

bool Market::SayaCreateBuyingEvent(string energyType)
{
	bool ans = false;
	if((energyType == "oil")&&(8<=sayaBuying ->getNameAmount(energyType)))
		ans = true;
	if((energyType == "gas")&&(8<=sayaBuying ->getNameAmount(energyType)))
		ans = true;
	if((energyType == "coal")&&(8<=sayaBuying ->getNameAmount(energyType)))
		ans = true;
	if((energyType == "sun")&&(5<=sayaBuying ->getNameAmount(energyType)))
		ans = true;
	if((energyType == "wind")&&(5<=sayaBuying ->getNameAmount(energyType)))
		ans = true;
	if((energyType == "smile")&&(3<=sayaBuying ->getNameAmount(energyType)))
		ans = true;
	if((energyType == "hug")&&(3<=sayaBuying ->getNameAmount(energyType)))
		ans = true;
	if(ans)
		sayaBuying->remove(energyType,sayaBuying->getNameAmount(energyType));
	return ans;
}
bool Market::SayaCreateSellingEvent(string energyType)
{
	bool ans = false;
	if((energyType == "oil")&&(1<=sayaSelling ->getNameAmount(energyType)))
		ans = true;
	if((energyType == "gas")&&(1<=sayaSelling ->getNameAmount(energyType)))
		ans = true;
	if((energyType == "coal")&&(1<=sayaSelling ->getNameAmount(energyType)))
		ans = true;
	if((energyType == "sun")&&(1<=sayaSelling ->getNameAmount(energyType)))
		ans = true;
	if((energyType == "wind")&&(1<=sayaSelling ->getNameAmount(energyType)))
		ans = true;
	if((energyType == "smile")&&(1<=sayaSelling ->getNameAmount(energyType)))
		ans = true;
	if((energyType == "hug")&&(1<=sayaSelling ->getNameAmount(energyType)))
		ans = true;
	if(ans)
	{
		sayaSelling->remove(energyType,sayaSelling->getNameAmount(energyType));
		sayaBuying->remove(energyType,sayaBuying->getNameAmount(energyType));
	}
	return ans;
}
double Market::getEnergyPrice(string energyType)
{
	return prices->getNameAmount(energyType);
}





